//
// Created by Luhang on 2023/4/19/019.
//

#ifndef INC_0217REVIEW_STRING_H
#define INC_0217REVIEW_STRING_H

#endif //INC_0217REVIEW_STRING_H

#include <iostream>
#include <cassert>
#include <cstring>
using std::cout;
using std::endl;

namespace Lu{
    class string{
    public:
        typedef char* iterator;
        typedef const char *const_iterator;

        iterator begin(){
            return _str;
        }

        iterator end(){
            return _str + _size;
        }

        const_iterator begin() const {
            return _str;
        }

        const_iterator end() const {
            return _str + _size;
        }

/*        //无参构造
        string()
        :_str(new char [1])
        ,_size(0)
        ,_capacity(0){
            _str[0] = '\0';
        }
        //有参构造
        string(const char *str)
        :_size(strlen(str)){
            _capacity = _size == 0 ? 3 : _size;
            _str = new char[_capacity + 1];
            strcpy(_str, str);
        }
        */
        //构造函数
        string(const char* str = "")
        :_size(strlen(str)){
            _capacity = _size == 0 ? 3 : _size;
            _str = new char[_capacity + 1];
            strcpy(_str, str);
        }

        //拷贝构造
        string(const string& s)
        :_size(s._size)
        ,_capacity(s._capacity){
            _str = new char[s._capacity + 1];
            strcpy(_str, s._str);
        }

        string& operator=(const string& s){
            //防止自己给自己赋值
            if (this != &s){
                //先开一个临时的，成功后再将_str释放，最后赋值
                char* tmp = new char[s._capacity + 1];
                strcpy(tmp,s._str);
                delete[] _str;
                _str = tmp;

                _size = s._size;
                _capacity = s._capacity;
            }
            return *this;
        }

        //析构函数
        ~string(){
            delete[] _str;
            _str = nullptr;
            _size = _capacity = 0;
        }

        const char* c_str(){
            return _str;
        }

        //普通对象可以调用，const对象也能调用
        size_t size() const{
            return _size;
        }

        size_t capacity() const{
            return _capacity;
        }

        char& operator[](size_t pos){
            assert(pos < _size);
            return _str[pos];
        }

        const char& operator[](size_t pos)const{
            assert(pos < _size);
            return _str[pos];
        }

        // 不修改成员变量数据的函数，最好都加上const
        bool operator>(const string &s) const {
            return strcmp(_str, s._str) > 0;
        }

        bool operator==(const string &s) const {
            return strcmp(_str, s._str) == 0;
        }

        bool operator>=(const string &s) const {
            //return *this > s || *this == s;
            return *this > s || s == *this;
        }

        bool operator<(const string &s) const {
            return !(*this >= s);
        }

        bool operator<=(const string &s) const {
            return !(*this > s);
        }

        bool operator!=(const string &s) const {
            return !(*this == s);
        }

        void resize(size_t n, char ch = '\0'){
            if (n < _size){
                _size = n;
                _str[_size] = '\0';
            } else if(n > _size){
                if (n > _capacity)
                    reserve(n);
                while (_size < n){
                    _str[_size] = ch;
                    ++_size;
                }
                _size = n;
                _str[_size] = '\0';
            }
        }

        void reserve(size_t n){
            if (n > _capacity){
                char* tmp = new char[n + 1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;

                _capacity = n;
            }
        }

        void push_back(char ch){
            if (_size + 1 > _capacity)
                reserve(2 * _capacity);

            _str[_size] = ch;
            ++_size;

            _str[_size] = '\0';
        }

        void append(const char* str){
            if (_size + strlen(str) > _capacity)
                reserve(_size + strlen(str));

            strcpy(_str + _size, str);
            _size += strlen(str);
        }

        string& insert(size_t pos, char ch){
            assert(pos <= _size);
            if (_size + 1 > _capacity)
                reserve(2 * _capacity);

            /*//此方法不行
            size_t end = _size;
            while (end >= pos){
                _str[end + 1] = _str[end];
                --end;
            }
            */
            size_t end = _size + 1;
            while (end > pos){
                _str[end] = _str[end-1];
                --end;
            }
            _str[pos] = ch;
            ++_size;

            return *this;
        }

        string& insert(size_t pos, const char* str){
            assert(pos <= _size);
            size_t len = strlen(str);
            if (_size + len > _capacity)
                reserve(_size + len);

            size_t end = _size + len;
            while (end > pos + len - 1){
                _str[end] = _str[end - len];
                --end;
            }
            strncpy(_str + pos, str,len);
            _size += len;

            return *this;
        }

        string& erase(size_t pos, size_t len = npos){
            assert(pos < _size);
            if (len == npos || pos + len >= _size){
                _str[pos] = '\0';
                _size = pos;
            } else{
                strcpy(_str + pos, _str + pos + len);
                _size -= len;
            }
            return *this;
        }

        void swap(string& s){
            std::swap(_str, s._str);
            std::swap(_capacity, s._capacity);
            std::swap(_size, s._size);
        }

        size_t find(char ch, size_t pos = 0){
            assert(pos < _size);
            for (size_t i = pos; i < _size; ++i) {
                if (_str[i] == ch)
                    return i;
            }
            return npos;
        }

        size_t find(const char* str, size_t pos = 0){
            assert(pos < _size);
            char* p = strstr(_str + pos, str);
            if (p == nullptr)
                return npos;
            else
                return p - _str;
        }

        string& operator+=(char ch){
            push_back(ch);
            return *this;
        }

        string& operator+=(const char* str){
            append(str);
            return *this;
        }

        void clear(){
            _str[0] = '\0';
            _size = 0;
        }

    private:
        char* _str;
        size_t _size;
        size_t _capacity;
        static size_t npos;
    };

    size_t string::npos = -1;

    std::ostream& operator<<(std::ostream& out, const string& s){
        for (auto ch : s) {
            out << ch;
        }
        return out;
    }

    std::istream& operator>>(std::istream& in, string& s){
        s.clear();
        char ch = in.get();
        char buff[128];
        size_t i = 0;
        while (ch != ' ' && ch != '\n'){
            buff[i++] = ch;
            if (i == 127){
                buff[127] = '\0';
                s += buff;
                i = 0;
            }
            ch = in.get();
        }
        if (i != 0){
            buff[i] = '\0';
            s += buff;
        }
        return in;
    }

    void Print(const string& s){
        for (int i = 0; i < s.size(); ++i) {
            cout << s[i] << " ";
        }
        cout << endl;
    }

    void test1(){
        string s1;
        std::cout << s1.c_str() << std::endl;
        string s2("hello");
        string s3(s2);
        s1 = s3;
        std::cout << s1.c_str() << std::endl;
        std::cout << s2.c_str() << std::endl;
        std::cout << s3.c_str() << std::endl;
    }

    void test2(){
        string s1;
        cout << s1.c_str() << endl;
        string s2("hello");
        cout << s2.c_str() << endl;
        s1 = s2;
        cout << s1.c_str() << endl;
        Print(s2);
    }

    void test3(){
        string s1("hello");
        cout << s1.c_str() << endl;
        for (int i = 0; i < s1.size(); ++i) {
            cout << ++s1[i] << " ";
        }
        cout << endl;
        string::iterator it = s1.begin();
        while (it != s1.end()){
            cout << *it;
            ++it;
        }
        cout << endl;
    }

    void test4(){
        string s1("hello world");
        string s2 = "hello chongqing";
        cout << (s1 < s2) << endl;
        cout << (s1 == s2) << endl;
        cout << (s1 > s2) << endl;
    }

    void test5(){
        string s1("hello world");
        cout << s1.c_str() << endl;
        cout << s1.size() << endl;
        cout << s1.capacity() << endl;

        s1.push_back('!');
        cout << s1.c_str() << endl;
        cout << s1.size() << endl;
        cout << s1.capacity() << endl;

        s1.append(" hello chongqing!");
        cout << s1.c_str() << endl;
        cout << s1.size() << endl;
        cout << s1.capacity() << endl;
    }

    void test6(){
        string s1("hello world");
        cout << s1.c_str() << endl;
        cout << s1.size() << endl;
        cout << s1.capacity() << endl;

        s1.resize(25,'!');
        cout << s1.c_str() << endl;
        cout << s1.size() << endl;
        cout << s1.capacity() << endl;

        s1.resize(5);
        cout << s1.c_str() << endl;
        cout << s1.size() << endl;
        cout << s1.capacity() << endl;
    }

    void test7(){
        string s1("hello world");
        cout << s1.c_str() << endl;
        cout << s1.size() << endl;
        cout << s1.capacity() << endl;

        s1.insert(5,"chongqing");
        cout << s1.c_str() << endl;
        cout << s1.size() << endl;
        cout << s1.capacity() << endl;
    }

    void test8(){
        string s1("hello world");
        //cout << s1.c_str() << endl;
        string s2 = "or";
        //cout << s2.c_str() << endl;
        //cout << strstr(s1.c_str(),s2.c_str()) << endl;
        cout << s1.find('o') << endl;
        cout << s1.find('o',5) << endl;
        cout << s1.find(s2.c_str()) << endl;
        cout << s1.find("world",8) << endl;
    }

    void test9(){
        string s1;
        std::string s2;
        cout << sizeof(s1) << endl;
        cout << sizeof(s2) << endl;
        string s3("hell0");
        std::string s4("hello");
        cout << sizeof(s1) << endl;
        cout << sizeof(s2) << endl;
        size_t a = 100;
        cout << sizeof(a);
    }
}
